﻿using Microsoft.Xna.Framework;
using System;
using Microsoft.Xna.Framework.Graphics;

namespace DDOS.Camera
{
    public class Camera3D
    {
        protected Vector3 position;
        /// <summary>
        /// The position of the camera.
        /// </summary>
        public virtual Vector3 Position
        {
            get
            {
                return position;
            }
            set
            {
                shouldUpdateViewMatrix = true;
                position = value;
            }
        }

        private Vector3 target;
        /// <summary>
        /// The position of the camera's target.
        /// </summary>
        public virtual Vector3 Target
        {
            get
            {
                return target;
            }
            set
            {
                shouldUpdateViewMatrix = true;
                target = value;
            }
        }

        private Vector3 up;
        /// <summary>
        /// The Vector3 indicating which way is 'up' for the camera (typically Vector3.Up is used).
        /// </summary>
        public Vector3 UpVector
        {
            get
            {
                return up;
            }
            set
            {
                shouldUpdateViewMatrix = true;
                up = value;
            }
        }

        /// <summary>
        /// The direction the camera is currently facing.
        /// </summary>
        public Vector3 Direction
        {
            get
            {
                return Target - Position;
            }
        }

        /// <summary>
        /// The direction the camera is currently facing, normalized so that all values are between 0.0 and 1.0.
        /// </summary>
        public Vector3 NormDirection
        {
            get
            {
                Vector3 dir = Target - Position;
                dir.Normalize();
                return dir;
            }
        }

        public Vector3 Left
        {
            get
            {
                Vector3 direction = Vector3.Cross(Vector3.Up, Direction);

                return direction;
            }
        }
        public Vector3 LeftNorm
        {
            get
            {
                Vector3 leftNorm = Left;
                leftNorm.Normalize();
                return leftNorm;

            }
        }

        public Vector3 Right
        {
            get
            {

                return -Left;
            }
        }
        public Vector3 RightNorm
        {
            get
            {
                Vector3 rightNorm = Right;
                rightNorm.Normalize();
                return rightNorm;

            }
        }

        /// <summary>
        /// The projection matrix (or 'lens') of the camera.
        /// </summary>
        public Matrix ProjectionMatrix { get; set; }

        private Matrix viewMatrix;
        private bool shouldUpdateViewMatrix = true;
        /// <summary>
        /// The calculated view matrix of the camera.
        /// </summary>
        public Matrix ViewMatrix
        {
            get
            {
                if (shouldUpdateViewMatrix)
                {
                    viewMatrix = Matrix.CreateLookAt(new Vector3(Position.X, Position.Y, Position.Z), Target, UpVector);
                    shouldUpdateViewMatrix = false;
                }
                return viewMatrix;
            }
        }


        /// <summary>
        /// Creates a new camera.
        /// </summary>
        /// <param name="position">The starting position of the camera</param>
        /// <param name="target">The camera's initial target (the thing at which it's looking)</param>
        /// <param name="upVector">The camera's initial up vector (Vector3.Up is typically used)</param>
        /// <param name="projectionMatrix">The projection matrix of the camera, see Matrix.CreatePerspectiveFieldOfView)</param>
        public Camera3D(Vector3 position, Vector3 target, Vector3 upVector, Matrix projectionMatrix)
        {
            Position = position;
            Target = target;
            UpVector = upVector;
            ProjectionMatrix = projectionMatrix;
        }

        public bool ShouldDraw(Vector3 objectPosition)
        {
            Vector3 directionTowardObject = objectPosition - Position;
            directionTowardObject.Normalize();
            return Vector3.Dot(Direction, directionTowardObject) > 0;
        }

        /// <summary>
        /// Override this method to allow for custom camera updates.
        /// </summary>
        /// <param name="gt"></param>
        public virtual void Update(GameTime gt)
        {
        }
    }
}
